class TwinkleTreeParser extends TreeParser;



options {
importVocab=TwinkleParser;

//backtrack=true;
}
{
	TwinkleApp appobj;
	TKeyListener keyListen;
	java.util.Hashtable dict = new java.util.Hashtable();
	Env env ;
	Hstack hs;
	java.util.ArrayList<String> al1 = new java.util.ArrayList<String>();
	static int RETURN_TRUE=1;
	static int BREAK_TRUE=2;
	String s=null;
}

program
{
	appobj= new TwinkleApp();
	appobj.display();
	keyListen = appobj.getKeyListener();
	//keyListen.setListen(true);
}
: (activity)* main;

activity: #(ACTIVITY ID subprogram:.) {TwinkleFunction.funcRegister(#ID.getText(), #subprogram);};

main{env = ActivationRecord.create_activation_record(null);}: #(MAIN subprogram2);

subprogram returns [int r=0]: #(SUBPROG {env.enter_scope();}r=stmts) {if (r==RETURN_TRUE) return RETURN_TRUE; env.leave_scope();};

subprogram2 returns [int r=0]: #(SUBPROG2 {env.enter_scope();}r=stmts2) {if (r==RETURN_TRUE) return RETURN_TRUE; env.leave_scope();};

stmts returns [int r= 0 ]: (r=stmt { if(r==RETURN_TRUE) return RETURN_TRUE; if(r==BREAK_TRUE) return BREAK_TRUE;})*;
stmts2 returns [int r= 0 ]: (r=stmt2 { if(r==RETURN_TRUE) return RETURN_TRUE; if(r==BREAK_TRUE) return BREAK_TRUE;})*;


// S&F from here
exp1 returns [boolean r=false]
	{boolean a;}
	:#(NOT a=bool){r=!a;System.out.println("bool "+a);}
	| (a=bool){r=a;  System.out.println("bool "+a);}
	;



bool returns [boolean r=false]

: TRUE {r=true;} 
| FALSE {r=false;}  
| #(ISPRESSED str:STRING )
{

System.out.print(" inside pressed: " +"\n");
//appobj.waitForKey();
String ss = #str.getText();
System.out.println("ss "+ss+ " ");
char c;
int key;
if (ss.equals("ESC"))
	{ 
	  c = '*';
	  key = 27;
	  System.out.println("key waited for Escape= " +key);
	}
else
	{ c = ss.charAt(0);
	  key = appobj.keyNo(c);
	}
System.out.println( "c "+c+ " ");


System.out.println("key waited for = " +key);
if (appobj.key==key )
{r=true;
System.out.println("key pressed = " +appobj.key);

System.out.println("right ");
}
else
{r=false;
System.out.println("wrong ");
}
}

;




expr returns [boolean r=false]
	{boolean a,b;}
	: #(AND a=expr b=expr){ r= a && b;}
	| #(OR a=expr b=expr){ r= a || b;}
	| a=exp1 {r=a;}
	;


val returns [String st=null] { System.out.print (" inside val ");}
	: s:STRING {st=(s.getText());}
	| n:NULL { st=""; }
	| #(ID (index:NUMBER)?)
	{ String sss=(#ID.getText());
		System.out.print (" inside val[i] "+ sss);
		if (#index==null)
		{st = (String) env.get_variable(#ID.getText());}
		else
		{
			java.util.ArrayList<String> list=(java.util.ArrayList<String>)env.get_variable(#ID.getText());
			st=list.get((int)Integer.parseInt(#index.getText()));
			System.out.print (" "+st+" ");
		}
	}
	
	;

valElement returns [String st=null] { System.out.print (" inside val ");}
	: s:STRING {st=(s.getText());}
	| n:NULL { st=""; }
	| ID 
	{ String sss=(#ID.getText());
		
		
			if ( env.get_variable(sss) instanceof java.util.ArrayList<?>)
			{
			
			System.out.print (" Array " + sss);
			java.util.ArrayList<String> list=(java.util.ArrayList<String>)env.get_variable(#ID.getText());
			int index=(int)Integer.parseInt((String)env.get_variable("itr"));
			System.out.print (" Index " + index);
			st=list.get(index);
			System.out.print (" "+st+" ");
			System.out.print (" inside val["+ index +"] "+ sss);
			}
			else
			st = (String)env.get_variable(sss);
	
		
		
	}
	;

listVal returns [String r=null]
	: n:NULL { r=null; }
	| ID {r = #ID.getText();}
	;



//val3 returns [boolean r=false]
// {boolean a,b;}
// : #(AND a=exp1 b=exp1){ r= a && b;}
// | #(OR a=exp1 b=exp1){ r= a || b;}
// | a=exp1 {r=a;}



//val2 : ID | STRING;
//val : ID | NULL | STRING;
//val_list : ID_list | NULL;
// S&F to here

stmt2 returns [int r=0] { boolean a=false; int itr=0;}
		: r= subprogram2 {if(r==RETURN_TRUE) return RETURN_TRUE;if(r==BREAK_TRUE) return BREAK_TRUE;}
		| #(START ID)
		{  //keyListen.setListen(false);
			env = ActivationRecord.create_activation_record(env);
			env.enter_scope();
			TwinkleFunction.funcCall(this, #ID.getText(), env);
			env.leave_scope();
			env =ActivationRecord.remove_activation_record(env);
			//keyListen = appobj.getKeyListener();
	//keyListen.setListen(true);
	}
	/* S&F from here*/
	| #(IF a=expr t1 :.(t2:.)? )
		{if(a!=false)
			{
				System.out.print (" inside if ");
				r=(stmt2(#t1));
			if (r==RETURN_TRUE)return RETURN_TRUE ;
			if (r==BREAK_TRUE)return BREAK_TRUE ;
			}
			
		else {
			System.out.print (" false ");
			if(#t2 != null)
			{
				System.out.print (" inside else ");
				r=(stmt2(#t2));
			if (r==RETURN_TRUE)return RETURN_TRUE ;
			if (r==BREAK_TRUE)return BREAK_TRUE ;}
		}
		}

	|#(WHILE w_expr :. w_body :. )
		{a= expr(#w_expr);
		while(a!=false)
		{ //keyListen.setListen(true);
r=(stmts2(#w_body));
//keyListen.setListen(false);
a= expr(#w_expr);
if (r==RETURN_TRUE)return RETURN_TRUE ;
if (r==BREAK_TRUE)
break ;
}
}
| #(SHOWMESSAGE message:. )
{

	String s =(val(message));
	
	appobj.showMessage(s);
	appobj.waitFor(2);
	 }

| #(SAY sound:. )
  { String s =(val(sound));
   appobj.say(s); }

	| (WAITFORKEY )
	{  
		appobj.waitForKey();
	}
	
 | #(WAIT NUMBER) 
	{  
		appobj.waitFor((long)Long.parseLong(#NUMBER.getText()));
	}
;	

stmt returns [int r=0] { boolean a=false; int itr=0;}
		: r= subprogram {if(r==RETURN_TRUE) return RETURN_TRUE;if(r==BREAK_TRUE) return BREAK_TRUE;}

		| r=decls {if(r==RETURN_TRUE) return RETURN_TRUE;if(r==BREAK_TRUE) return BREAK_TRUE;}
		
|#(LOOP num1:NUMBER num2:NUMBER loop_body:.
{ itr=0;int f=0 ; int t=0;
f=(int)Integer.parseInt(#num1.getText());
t=(int)Integer.parseInt(#num2.getText());


int times= Math.abs(t-f)+1;
itr= f;
env.add_in_present_scope("itr",Integer.toString(itr));

//if(env.check_in_present_scope("itr")==true)
//{
//		System.out.print (" yes " );
//}
//else 
//System.out.print (" no " );
//
//System.out.print (" from loop ii " );
//
//int iii=(int)Integer.parseInt((String)env.get_variable("itr"));
//System.out.print (" from loop Index " + iii);

while(times>0)
{ if (loop_body != null)
{
r= stmt(#loop_body);
if (r==RETURN_TRUE)return RETURN_TRUE ;
if (r==BREAK_TRUE)
break ;
}
if (f>t)
itr--;
else 
itr++;
env.add_in_present_scope("itr",Integer.toString(itr));
times--;
}
} )



| #(SHOW ID (numb:NUMBER)?) // another version
{
if (!( env.get_variable(#ID.getText()) instanceof Element))
{
System.out.println(" Incompatible Assignment ");
System.exit(0);
}
Object obj=env.get_variable(#ID.getText());
if (#numb!=null)
appobj.show((Element)obj, (int)Integer.parseInt(#numb.getText()));
else
appobj.show((Element)obj);
}

| #(SHOWELEMENT id_1:. id_2:. id_3:. id_4:. sl:NUMBER) // COMMA! NUMBER RPAREN!;
{
System.out.print (" inside show "); // takes null in addition to ID
String text =(#val(id_1));
String picture =(#val(id_2));
String sound2 =(#val(id_3));
String color =(#val(id_4));
int sleep = (int)Integer.parseInt(#sl.getText());
System.out.print (" "+ text +" "+picture+ " "+ sound2+" "+ color);
appobj.show(new Element(text,picture,sound2,color),sleep);

}

| #(SHOWALL list11:. list22:. list33:. list44:. num:NUMBER) // COMMA! NUMBER RPAREN!;
{
if (!( env.get_variable(#list11.getText()) instanceof java.util.ArrayList<?>))
{
System.out.println(" Incompatible Assignment ");
System.exit(0);
}
if (!( env.get_variable(#list22.getText()) instanceof java.util.ArrayList<?>))
{
System.out.println(" Incompatible Assignment ");
System.exit(0);
}
if (!( env.get_variable(#list33.getText()) instanceof java.util.ArrayList<?>))
{
System.out.println(" Incompatible Assignment ");
System.exit(0);
}
if (!( env.get_variable(#list44.getText()) instanceof java.util.ArrayList<?>))
{
System.out.println(" Incompatible Assignment ");
System.exit(0);
} // takes null in addition to ID
java.util.ArrayList<String> aobjw=(java.util.ArrayList<String>)env.get_variable(#listVal(list11) );
java.util.ArrayList<String> aobjp=(java.util.ArrayList<String>)env.get_variable(#listVal(list22));
java.util.ArrayList<String> aobjs=(java.util.ArrayList<String>)env.get_variable(#listVal(list33));
java.util.ArrayList<String> aobjc=(java.util.ArrayList<String>)env.get_variable(#listVal(list44));
appobj.showAll(aobjw,aobjp,aobjs,aobjc,(long)Long.parseLong(#num.getText()) );
}


| #(SHOWIFPRESSED list1:. list2:. list3:. list4:. list5:. wait:NUMBER)
{
	if (!( env.get_variable(#list1.getText()) instanceof java.util.ArrayList<?>))
	{
		System.out.println(" Incompatible Assignment ");
		System.exit(0);
	}
	if (!( env.get_variable(#list2.getText()) instanceof java.util.ArrayList<?>))
	{
		System.out.println(" Incompatible Assignment ");
		System.exit(0);
	}
	if (!( env.get_variable(#list3.getText()) instanceof java.util.ArrayList<?>))
	{
		System.out.println(" Incompatible Assignment ");
		System.exit(0);
	}
	if (!( env.get_variable(#list4.getText()) instanceof java.util.ArrayList<?>))
	{
		System.out.println(" Incompatible Assignment ");
		System.exit(0);
	}
	if (!( env.get_variable(#list5.getText()) instanceof java.util.ArrayList<?>))
	{
		System.out.println(" Incompatible Assignment ");
		System.exit(0);
	}
// takes null in addition to ID
	java.util.ArrayList<String> aobjw=(java.util.ArrayList<String>)env.get_variable(#listVal(list1));
	java.util.ArrayList<String> aobjp=(java.util.ArrayList<String>)env.get_variable(#listVal(list2));
	java.util.ArrayList<String> aobjs=(java.util.ArrayList<String>)env.get_variable(#listVal(list3));
	java.util.ArrayList<String> aobjc=(java.util.ArrayList<String>)env.get_variable(#listVal(list4));
	java.util.ArrayList<String> aobjk=(java.util.ArrayList<String>)env.get_variable(#listVal(list5));
	 //appobj.lock=1;
	 long waitTime=(long)Long.parseLong(#wait.getText());
	 System.out.println(" Wait  "+ waitTime);
    appobj.showIfPressed(aobjw,aobjp,aobjs,aobjc,aobjk,waitTime);
  //  appobj.waitFor((long)Long.parseLong(#wait.getText()));
   
   // appobj.waitFor(2);
   // appobj.lock=0;
}
| #(SHOWANDTEST wordList:. imageList:. answerList:. colorList:. keyList:. question:. )
{
if (!( env.get_variable(#wordList.getText()) instanceof java.util.ArrayList<?>))
{
System.out.println(" Incompatible Assignment ");
System.exit(0);
}
if (!( env.get_variable(#imageList.getText()) instanceof java.util.ArrayList<?>))
{
System.out.println(" Incompatible Assignment ");
System.exit(0);
}
if (!( env.get_variable(#colorList.getText()) instanceof java.util.ArrayList<?>))
{
System.out.println(" Incompatible Assignment ");
System.exit(0);
}
if (!( env.get_variable(#answerList.getText()) instanceof java.util.ArrayList<?>))
{
System.out.println(" Incompatible Assignment ");
System.exit(0);
}
if (!( env.get_variable(#keyList.getText()) instanceof java.util.ArrayList<?>))
{
System.out.println(" Incompatible Assignment ");
System.exit(0);
}
// takes null in addition to ID
java.util.ArrayList<String> aobjw=(java.util.ArrayList<String>)env.get_variable(#listVal(wordList));
java.util.ArrayList<String> aobjp=(java.util.ArrayList<String>)env.get_variable(#listVal(imageList));
java.util.ArrayList<String> aobjs=(java.util.ArrayList<String>)env.get_variable(#listVal(colorList));
java.util.ArrayList<String> aobjc=(java.util.ArrayList<String>)env.get_variable(#listVal(answerList));
java.util.ArrayList<String> aobjk=(java.util.ArrayList<String>)env.get_variable(#listVal(keyList));
String questionString =(#val(question));
appobj.showAndTest(aobjw,aobjp,aobjs,questionString,aobjc,aobjk);
}

//#
| (WAITFORKEY )
	{  
		appobj.waitForKey();
	}
	
 | #(WAIT NUMBER) 
	{  
		appobj.waitFor((long)Long.parseLong(#NUMBER.getText()));
	}
;

//##







/* S&F to here*/


decls returns [int r=0]
: r=vardec {if(r==RETURN_TRUE) return RETURN_TRUE;if(r==BREAK_TRUE) return BREAK_TRUE;}
| r=elementdec {if(r==RETURN_TRUE) return RETURN_TRUE; if(r==BREAK_TRUE) return BREAK_TRUE;}
| r=listdec {if(r==RETURN_TRUE) return RETURN_TRUE; if(r==BREAK_TRUE) return BREAK_TRUE;}
;

vardec returns [int r=0]
: #(VAR ID str1:STRING
{

	if(env.check_in_present_scope(#ID.getText())==true ||(str1.getText()=="itr") )
	{
		System.out.println("Duplicate Variable Definition  ::"+(#ID.getText()));
		System.exit(0);
		
	}
	else
	{
		env.add_in_present_scope(#ID.getText(),str1.getText());
	}
	
}
)
;

elementdec returns [int r=0]
: #(ELEMENT ID element_var1:. element_var2:. element_var3:. element_var4:.)
{
	String ele_var1 = valElement(element_var1);
	String ele_var2 = valElement(element_var2);
	String ele_var3 = valElement(element_var3);
	String ele_var4 = valElement(element_var4);

Element e = new Element(ele_var1, ele_var2, ele_var3, ele_var4);

if(env.check_in_present_scope(#ID.getText())==true)
{
		System.out.println("Duplicate Variable Definition  ::"+#ID.getText());
		System.exit(0);
}
else
{
env.add_in_present_scope(#ID.getText(),e);
}
if(env.get_variable(#ID.getText())==null)////// y is this here?
{
System.out.println("Variable "+#ID.getText()+ "not found");
System.exit(0);
}
};

element_var returns [String s = null] {}
: (mem1:STRING
{
System.out.println("Inside mem1");
s = #mem1.getText();
}
)
|
(mem2:ID
{
System.out.println("Inside mem2");
if(env.get_variable(#mem2.getText()) == null )
{
System.out.println("Variable not found");
System.exit(1);
}
s = (String)env.get_variable(#mem2.getText());
}
)
| (mem3:NULL
{
System.out.println("Inside mem3");
s = "";
}
)
;



listdec returns [int r=0] {java.util.ArrayList<String> lst=new java.util.ArrayList<String>();}
: #(LIST ID
( mem:STRING
{lst.add((#mem).getText());}

)*
// (col:COLOR
// {
// String s=color(col);
// System.out.println("Inside Colour");
// lst.add((#col).getText());
// }
// )*
{
	if(env.check_in_present_scope(#ID.getText())==true)
	{
		System.out.println("Duplicate variable definition ::"+#ID.getText());
		System.exit(0);	
	}
	else
	{
		env.add_in_present_scope(#ID.getText(),lst);	
	}

	if (env.get_variable(#ID.getText())==null)//again y is this here?
	{
		System.out.println("Variable "+#ID.getText()+ " not found");
		System.exit(0);
	}
});